package com.framework.bdf4j.sysadm.service.impl;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.framework.bdf4j.comm.Constants;
import com.framework.bdf4j.comm.persist.DataScope;
import com.framework.bdf4j.msg.entity.vo.SysUserVO;
import com.framework.bdf4j.sysadm.entity.SysRole;
import com.framework.bdf4j.sysadm.entity.SysUser;
import com.framework.bdf4j.sysadm.entity.SysUserRole;
import com.framework.bdf4j.sysadm.mapper.SysUserMapper;
import com.framework.bdf4j.sysadm.service.SysMenuService;
import com.framework.bdf4j.sysadm.service.SysRoleService;
import com.framework.bdf4j.sysadm.service.SysUserRoleService;
import com.framework.bdf4j.sysadm.service.SysUserService;
import com.framework.bdf4j.sysadm.vo.MenuVO;
import com.framework.bdf4j.sysadm.vo.UserInfo;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
    private final SysMenuService sysMenuService;
    private final SysRoleService sysRoleService;
    private final SysUserRoleService sysUserRoleService;

    /**
     * 保存用户信息
     *
     * @param userDto
     *            DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean registerUser(SysUser userVo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userVo, sysUser);
        sysUser.setDelFlag(Constants.STATUS_NORMAL);
        sysUser.setPassword(ENCODER.encode(userVo.getPassword()));
        baseMapper.insert(sysUser);
        return Boolean.TRUE;
    }

    /**
     * 通过查用户的全部信息
     *
     * @param sysUser
     *            用户
     * @return
     */
    @Override
    public UserInfo findUserInfo(SysUser sysUser) {
        UserInfo userInfo = new UserInfo();
        userInfo.setSysUser(sysUser);
        // 设置角色列表 （ID）
        List<Integer> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()).stream().map(SysRole::getRoleId)
            .collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));

        // 设置权限列表（menu.permission）
        Set<String> permissions = new HashSet<>();
        Set<Integer> menus = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<MenuVO> permissionList = sysMenuService.findMenuByRoleId(roleId);
            for (MenuVO mvo : permissionList) {
                if (Constants.MENU.equals(mvo.getType())) {
                    menus.add(mvo.getMenuId());
                } else {
                    if (StringUtils.isNotEmpty(mvo.getPermission())) {
                        permissions.add(mvo.getPermission());
                    }
                }

            }
        });
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
        userInfo.setMenus(ArrayUtil.toArray(menus, Integer.class));
        return userInfo;
    }

    /**
     * 分页查询用户信息（含有角色信息）
     *
     * @param page
     *            分页对象
     * @param userDTO
     *            参数列表
     * @return
     */
    @Override
    public IPage getUsersWithRolePage(Page page, SysUser userDTO) {
    	QueryWrapper<SysUser> ew = new QueryWrapper<SysUser>();
    	ew.eq("u.del_flag", "0")
    	.like(StrUtil.isNotBlank(userDTO.getLoginname()), "u.loginname", userDTO.getLoginname())
    	.like(StrUtil.isNotBlank(userDTO.getUsername()), "u.username", userDTO.getUsername())
    	.eq(userDTO.getDeptId() != null, "u.dept_id", userDTO.getDeptId())
    	.likeRight(StrUtil.isNotBlank(userDTO.getPhone()), "u.phone", userDTO.getPhone())
    	.eq(StrUtil.isNotBlank(userDTO.getLockFlag()), "u.lock_flag", userDTO.getLockFlag());
        return baseMapper.getUserVosPage(page, ew, new DataScope());
    }

    /**
     * 查询所有用户信息（含有角色信息）
     *
     * @param userDTO
     *            参数列表
     * @return
     */
    @Override
    public List<SysUser> getUsersWithRole(SysUser userDTO) {
    	QueryWrapper<SysUser> ew = new QueryWrapper<SysUser>();
    	ew.eq("u.del_flag", "0")
    	.like(StrUtil.isNotBlank(userDTO.getLoginname()), "u.loginname", userDTO.getLoginname())
    	.like(StrUtil.isNotBlank(userDTO.getUsername()), "u.username", userDTO.getUsername())
    	.eq(userDTO.getDeptId() != null, "u.dept_id", userDTO.getDeptId())
    	.likeRight(StrUtil.isNotBlank(userDTO.getPhone()), "u.phone", userDTO.getPhone())
    	.eq(StrUtil.isNotBlank(userDTO.getLockFlag()), "u.lock_flag", userDTO.getLockFlag());
        return baseMapper.getUserVos(ew, new DataScope());
    }

    /**
     * 通过ID查询用户信息
     *
     * @param id
     *            用户ID
     * @return 用户信息
     */
    @Override
    public SysUser selectUserVoById(Integer id) {
        return baseMapper.getUserVoById(id);
    }

    /**
     * 删除用户
     *
     * @param sysUser
     *            用户
     * @return Boolean
     */
    @Override
    @CacheEvict(value = Constants.USER_DETAILS, key = "#sysUser.loginname")
    public Boolean deleteUserById(SysUser sysUser) {
        sysUserRoleService.deleteByUserId(sysUser.getUserId());
        this.removeById(sysUser.getUserId());
        return Boolean.TRUE;
    }

    @Override
    @CacheEvict(value = Constants.USER_DETAILS, key = "#sysUser.loginname")
    public Boolean updateUser(SysUser sysUser) {
        sysUser.setUpdateTime(new Date());

        if (StrUtil.isNotBlank(sysUser.getPassword())) {
            sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
        }
        this.updateById(sysUser);

        sysUserRoleService
            .remove(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, sysUser.getUserId()));
        sysUser.getRoleIds().forEach(roleId -> {
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(sysUser.getUserId());
            userRole.setRoleId(roleId);
            userRole.insert();
        });
        return Boolean.TRUE;
    }

    /**
     * 保存用户信息
     *
     * @param userDto
     *            DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(SysUser sysUser) {
        sysUser.setDelFlag(Constants.STATUS_NORMAL);
        sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
        baseMapper.insert(sysUser);
        List<SysUserRole> userRoleList = sysUser.getRoleIds().stream().map(roleId -> {
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(sysUser.getUserId());
            userRole.setRoleId(roleId);
            return userRole;
        }).collect(Collectors.toList());
        for (SysUserRole sysUserRole : userRoleList) {
        	sysUserRoleService.save(sysUserRole);
		}
        return true;
    }

    @Override
    public List<Integer> getUserListByRoleId(List<Integer> roleIds) {
        return this.getBaseMapper().getUserListByRoleIds(roleIds);
    }

    @Override
    public List<Integer> getUserListByDepartId(List<Integer> deptIds) {
        return this.getBaseMapper().getUserListByDepartIds(deptIds);
    }

    @Override
    public List<SysUserVO> getUserInfoByMsgId(Integer msgId) {
        return this.getBaseMapper().getUserInfoByIds(msgId);
    }
}
